package com.tony.juc;

import java.util.Map;
import java.util.concurrent.*;

/**
 * Created with IntelliJ IDEA.
 *
 * @Title: DataCacheDemo001
 * @Auther: 皮蛋布丁
 * @Date: 2022/04/17/16:17
 * @Description: 数据缓存
 */
public class DataCacheDemo001 {

    public static void main(String[] args) throws Exception {
        //在缓存的外部只是对核心的数据类型进行了定义，而缓存内部会有其他的包装
        Cache<Long,News> cache = new Cache<>(); //定义缓存实现类
        cache.put(1L,new News(1L,"皮蛋布丁"));
        cache.put(2L,new News(2L,"Tony"));
        System.out.println(cache.get(1L));
        System.out.println(cache.get(2L));
        System.err.println("-----------------------清理分割线---------------------");
        TimeUnit.SECONDS.sleep(3); //3秒之后的数据一定被清除了
    }
}
class Cache<K,V> { //直接通过类的形式进行定义
    //缓存的内部必须要考虑到多线程下的资源安全以及性能操作
    private Map<K,V> cacheObjects = new ConcurrentHashMap<>(); // 并发集合
    //缓存的时间可以统一设置一个常量来进行定义，本次定义为2秒
    private static final long DELAY_SENCOND = 2;
    private static final TimeUnit TIME_UNIT = TimeUnit.SECONDS; //时间单元
    //因为现在牵扯到缓存数据的清除问题，那么清除问题可以考虑通过延迟队列来完成
    private BlockingQueue<DelayedItem<Pair>> queue = new DelayQueue();
    public Cache() { //构造方法
        Thread thread = new Thread(()->{ //创建一个新的线程对象
            while (true) { //持续的消除
                try {
                    DelayedItem<Pair> item = Cache.this.queue.take(); //获取弹出的数据
                    if (item != null) {
                        Pair pair = item.getItem(); //获取内容
                        Cache.this.cacheObjects.remove(pair.key,pair.value); //删除数据
                    }
                    TimeUnit.SECONDS.sleep(1); //每秒清除一次
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        //这个线程负责数据的清理，但是清理的工作都属于后台的工作，后台工作需要后台线程
        thread.setDaemon(true); //设置守护线程
        thread.start();//启动守护线程
    }
    public void put(K key,V value) throws Exception { //内容设置
        V oldValue = this.cacheObjects.put(key,value); //保存的同时返回旧的数据
        //所有的数据内容是被保存在队列之中的，既然设置了内容，如果重复的时候应该更新时间
        if (oldValue != null) { //数据重复保存
            this.queue.remove(oldValue); //删除数据
        }
        this.queue.put(new DelayedItem<Pair>(new Pair(key,value),DELAY_SENCOND,TIME_UNIT));
    }
    public V get(K key) { //红黑树是代表查询的最高性能了
        return this.cacheObjects.get(key); //通过Map获取数据
    }
    private class Pair { //定义缓存的数据项
        private K key;
        private V value;
        public Pair(K key,V value) {
            this.key = key;
            this.value = value;
        }
    }
    private class DelayedItem<T> implements Delayed {
        private T item; //缓存项
        private long delay; //时长
        private long start; //开始时间
        public DelayedItem(T item,long delay,TimeUnit unit) {
            this.item = item;
            this.delay = TimeUnit.MINUTES.convert(delay,unit); //延迟时间
            this.start = System.currentTimeMillis(); //当前时间
        }

        @Override
        public long getDelay(TimeUnit unit) {
            return unit.convert((this.start + this.delay) - System.currentTimeMillis(),TimeUnit.MILLISECONDS);
        }

        @Override
        public int compareTo(Delayed o) {
            return (int) (this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS));
        }
        public T getItem() {
            return item;
        }
    }
}
class News { //没有绯闻怎么能够成为明星呢？
    private long nid;
    private String title;
    public News(long nid,String title) {
        this.nid = nid;
        this.title = title;
    }
    public String toString() {
        return "【新闻数据】新闻编号：" + this.nid + "、新闻标题：" + this.title;
    }

}
